#pragma once

#include "VulkanRHI.h"
#include "Texture/RHISampler.h"
#include "Texture/RHITexture.h"
#include "Tradition/ColorBlendAttachment.h"
#include "../Misc/Timer.h"
#include "Tradition/RHISemaphore.h"

class RenderProcess;

class SwapChain;
class ImguiGUI;

#define USE_IMGUI 1

class RenderState
{
	friend class RHIBuffer;
	friend class BufferView;
	friend class RHITexture;
	friend class RHIPipeline;
	friend class RHIRenderPass;
	friend class RHIFrameBuffer;
	friend class AccelerationStructure;
	friend class RHIDescriptor;
	friend class RayTracingPipeline;
	friend class GameState;
	friend class GameScene;
	friend class RenderProcess;
	friend class RHICommandBuffer;
	friend class RHIFence;
	friend class RHISemaphore;

public:

	RenderState();

	~RenderState();

	void Init();

	void WaitForGame();

	void MainLoop();

	void AddWaitSemaphore(RefCountPtr<RHISemaphore> semaphore);

	void AddSignalSemaphore(RefCountPtr<RHISemaphore> semaphore);

	void SubmitTexture(RefCountPtr<RHITexture> texture);

	void SubmitFrame();

	void NextFrame();

	void OnResize();

	void Stop();

	void Exit();

	bool IsSubmitTexture() const;

	void ResetSubmitState();

	VkCommandBuffer BeginSingleCommand(VkQueueFlagBits queueFlags = VK_QUEUE_GRAPHICS_BIT);

	void FlushSingleCommand(VkCommandBuffer commandBuffer, VkQueueFlagBits queueFlags = VK_QUEUE_GRAPHICS_BIT);

	VkCommandPool GetCommandPool(VkQueueFlagBits queueFlags = VK_QUEUE_GRAPHICS_BIT) const;

	VkCommandBuffer GetImmediateCommandBuffer() const;

public:

	uint32 GetFrameIndex() const;

	uint32 GetFrameCount() const;

	uint64 GetFrameAmount() const;

	HANDLE GetFrameEvent(uint32 index);

	uint32 GetWidth() const;

	uint32 GetHeight() const;

	VkFormat GetSwapChainFormat() const;

	VkViewport& GetViewport();

	VkRect2D& GetScissor();

	VkPipelineViewportStateCreateInfo GetViewportState() const;

	float GetTotalTime() const;

	float GetDeltaTime() const;

	uint32 GetFps() const;

	RefCountPtr<RHITexture> GetDefaultTexture();

protected:

	void CreateCommandPool();

	void CreateSwapchain();

	void CreateStateResource();

public:

	RefCountPtr<RHISampler> GetSamplerByHash(uint32 hash) const;

	void RegisterSampler(uint32 hash, RefCountPtr<RHISampler> sampler);

	RefCountPtr<ColorBlendAttachment> GetColorBlendAttachmentByHash(uint32 hash) const;

	void RegisterColorBlendAttachment(uint32 hash, RefCountPtr<ColorBlendAttachment> colorBlendAttachment);

protected:

	void GarbageCollection();

	void DelayGCAccelerationStructure(VkAccelerationStructureKHR accelerationStructure);

	void DelayGCBuffer(VkBuffer buffer);

	void DelayGCBufferView(VkBufferView bufferView);

	void DelayGCImage(VkImage image);

	void DelayGCImageView(VkImageView imageView);

	void DelayGCPipeline(VkPipeline pipeline);

	void DelayGCFrameBuffer(VkFramebuffer frameBuffer);

	void DelayGCRenderPass(VkRenderPass renderPass);

	void DelayGCPipelineLayout(VkPipelineLayout pipelineLayout);

	void DelayGCDescriptorSetLayout(VkDescriptorSetLayout descriptorSetLayout);

	void DelayGCDescriptorPool(VkDescriptorPool descriptorPool);

	void DelayGCDeviceMemory(VkDeviceMemory deviceMemory);

	void DelayGCCommandBuffer(VkQueueFlagBits queueFlag, std::vector<VkCommandBuffer> commandBuffers);

	void DelayGCFence(VkFence fence);

	void DelayGCSemaphore(VkSemaphore semaphore);

protected:

	/**************************************/
	/*           GC Render Graph          */
	/**************************************/

	std::vector<VkAccelerationStructureKHR> mGCAccelerationStructureMap;

	std::vector<VkBuffer> mGCBufferMap;

	std::vector<VkBufferView> mGCBufferViewMap;

	std::vector<VkDeviceMemory> mGCDeviceMemoryMap;

	std::vector<VkImage> mGCImageMap;

	std::vector<VkImageView> mGCImageViewMap;

	std::vector<VkPipeline> mGCPipelineMap;

	std::vector<VkFramebuffer> mGCFrameBufferMap;

	std::vector<VkRenderPass> mGCRenderPassMap;

	std::vector<VkPipelineLayout> mGCPipelineLayoutMap;

	std::vector<VkDescriptorSetLayout> mGCDescriptorSetLayoutMap;

	std::vector<VkDescriptorPool> mGCDescriptorPoolMap;

	std::vector<std::pair<VkQueueFlagBits, std::vector<VkCommandBuffer>>> mGCCommandBufferMap;

	std::vector<VkFence> mGCFenceMap;

	std::vector<VkSemaphore> mGCSemaphoreMap;

	/**************************************/
	/*   Not GC Resource, GC Until Exit   */
	/**************************************/

	std::unordered_map<uint32, RefCountPtr<RHISampler>> mSamplerMap;

	std::unordered_map<uint32, RefCountPtr<ColorBlendAttachment>> mColorBlendAttachmentMap;

	RefCountPtr<RHITexture> mLogoTexture;

	std::vector<RefCountPtr<RHITexture>> mSubmitTexures;

	/**************************************/
	/*           Common Resource          */
	/**************************************/

	VkCommandPool mGraphicsCommandPool;

	VkCommandPool mComputeCommandPool;

	VkCommandPool mTransferCommandPool;

	SwapChain* mSwapChain;

	ImguiGUI* mImguiGUI;

	uint32 mFrameIndex;

	uint32 mFrameCount;

	std::vector<HANDLE> mFrameEvents;

	uint64 mFrameAmount;

	VkViewport mViewport;

	VkRect2D mScissor;

	VkPipelineViewportStateCreateInfo mViewportState;

	Timer mRenderTimer;

	bool mIsSubmitTexture;

	VkCommandBuffer mImmediateCommandBuffer;

	std::vector<RenderProcess*> mRenderProcessMap;
};